package cc.rengu.igas.channel.xmup.core.service.base;

import cc.rengu.igas.channel.xmup.common.constant.XmupParamConstant;
import cc.rengu.igas.channel.xmup.common.constant.XmupTreeNodeConstant;
import cc.rengu.igas.channel.xmup.common.util.XmupSecurityUtil;
import cc.rengu.igas.channel.xmup.core.model.ChnlBizResponse;
import cc.rengu.igas.channel.xmup.facade.base.BaseRequest;
import cc.rengu.igas.channel.xmup.facade.bean.PayerInfo;
import cc.rengu.igas.channel.xmup.facade.bean.RiskCtrlInfo;
import cc.rengu.igas.channel.xmup.facade.bean.TokenPayInfo;
import cc.rengu.oltp.service.base.RadpService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.DstChannelInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.DstChannelInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.DstChannelInfo;
import cc.rengu.oltp.service.common.entity.DstTxnAuthCfg;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.utility.util.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.util.Map;

/**
 * 支付业务处理基类
 */
public abstract class PayService<T> extends RadpService {
    @Override
    protected int bizInit(String s) {
        return 0;
    }

    @Override
    protected int bizProcess(String s, int i) {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        try {
            /* Step1：通道(交易)权限检查 */
            rglog.info("---------------> 通道(交易)权限检查 <---------------");
            channelPermissionCheck();
            /* Step2：业务处理前实现接口 */
            rglog.info("---------------> 业务处理前处理 <---------------");
            T request = beforeBizProcess();

            /* Step3：公共字段统一处理 */

            /* Step4：业务逻辑处理 */
            rglog.info("---------------> 业务逻辑处理 <---------------");
            ChnlBizResponse response = callBizService(request);
            /* Step4：业务处理后实现接口 */
            rglog.info("---------------> 业务处理后处理 <---------------");
            afterBizProcess(response);
        } catch (Exception e) {
            String respCode;
            String respDesc;
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            rglog.error("业务异常信息:<{}>", byteArrayOutputStream.toString());
            if (e instanceof BizException) {
                respCode = ((BizException) e).getCode();
                respDesc = e.getMessage();
                rglog.error("业务处理失败，业务返回码:<{}>，业务返回信息:<{}>", respCode, respDesc);
            } else {
                rglog.error("系统处理失败，返回信息:<{}>", e);
                respCode = OltpRpcdEnum.OLTP_PROCESS_ERROR.getRespCode();
                respDesc = OltpRpcdEnum.OLTP_PROCESS_ERROR.getRespDesc();
            }
            try {
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_CODE, respCode);
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_DESC, respDesc);
            } catch (Exception ex) {
                ex.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
                rglog.error("设置节点值异常信息:<{}>", byteArrayOutputStream.toString());
                return -1;
            }

        }
        return 0;
    }

    @Override
    protected int bizTerminate(String s) {
        return 0;
    }

    /**
     * 业务调用前处理
     *
     * @return 业务处理请求结构
     */
    protected abstract T beforeBizProcess() throws Exception;

    /**
     * 业务处理服务调用
     *
     * @param request 业务处理信息
     * @return 业务处理应答结果
     */
    protected abstract ChnlBizResponse callBizService(T request) throws Exception;

    /**
     * 业务调用后处理
     *
     * @param response 业务响应结果
     */
    protected abstract void afterBizProcess(ChnlBizResponse response) throws Exception;

    /**
     * 通道、交易权限权限
     *
     * @throws Exception 业务处理异常
     */
    private void channelPermissionCheck() throws Exception {
        BaseRequest baseRequest = new BaseRequest();
        ConvertUtil.convertOutput(baseRequest);
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String instId = baseRequest.getHeader().getInstId();
        String txnNum = baseRequest.getHeader().getTxnNum();
        /* 通道状态检查 */
        String dstChannelKey = instId + ChannelEnum.XMUP.getChannelType();
        DstChannelInfo dstChannelInfo = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_ISS_INFO_CACHE, dstChannelKey), DstChannelInfo.class);
        if (null == dstChannelInfo) {
            DstChannelInfoMapper dstChannelInfoMapper = new DstChannelInfoMapperImpl();
            dstChannelInfo = dstChannelInfoMapper.selectDstChannelInfoByPrimaryKey(instId, ChannelEnum.XMUP.getChannelType());
        }
        if (null == dstChannelInfo || !dstChannelInfo.getDstChannelStatus().equalsIgnoreCase(AppParamConstant.YES)) {
            rglog.error("支付渠道<{}-{}>未配置或已停用！", ChannelEnum.UPQC.getChannelType(), (null == dstChannelInfo) ? "" : dstChannelInfo.getDstChannelName());
            throw new BizException(OltpRpcdEnum.CHANNEL_DISABLED);
        }
        xmlTreeUtil.setXmlTreeObjectValue(XmupTreeNodeConstant.DST_CHANNEL_INFO, dstChannelInfo);

        String dstChannelAuthKey = instId.trim() + ChannelEnum.XMUP.getChannelType() + txnNum.trim();
        DstTxnAuthCfg dstTxnAuthCfg = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_TXN_CACHE, dstChannelAuthKey), DstTxnAuthCfg.class);
        if (null == dstTxnAuthCfg || !dstTxnAuthCfg.getSupportFlag().equalsIgnoreCase(AppParamConstant.YES)) {
            rglog.error("支付通道<{}-{}>不支持此交易，通道交易码:<{}>", dstChannelInfo.getDstChannelId(), dstChannelInfo.getDstChannelName(), txnNum);
            throw new BizException(OltpRpcdEnum.TRANS_NOT_SUPPORT);
        }
        if (dstTxnAuthCfg.getMsgRegisterFlag() != null && dstTxnAuthCfg.getMsgRegisterFlag().isEmpty()) {
            xmlTreeUtil.setXmlTreeStringValue(XmupTreeNodeConstant.MSG_REG_FLAG, dstTxnAuthCfg.getMsgRegisterFlag());
        }
    }

    /**
     * 支付标识化信息KV转换处理
     *
     * @param tokenPayInfo 支付标记化信息
     */
    protected void packageTokenPayInfo(TokenPayInfo tokenPayInfo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        StringBuilder tokenPayData = new StringBuilder(XmupParamConstant.LEFT_BRACE);
        if (null != tokenPayInfo.getToken() && !tokenPayInfo.getToken().isEmpty()) {
            tokenPayData.append(XmupTreeNodeConstant.token + XmupParamConstant.EQUAL).append(tokenPayInfo.getToken()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != tokenPayInfo.getTrId() && !tokenPayInfo.getTrId().isEmpty()) {
            tokenPayData.append(XmupTreeNodeConstant.trId + XmupParamConstant.EQUAL).append(tokenPayInfo.getTrId()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != tokenPayInfo.getTokenLevel() && !tokenPayInfo.getTokenLevel().isEmpty()) {
            tokenPayData.append(XmupTreeNodeConstant.tokenLevel + XmupParamConstant.EQUAL).append(tokenPayInfo.getTokenLevel()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != tokenPayInfo.getTokenBegin() && !tokenPayInfo.getTokenBegin().isEmpty()) {
            tokenPayData.append(XmupTreeNodeConstant.tokenBegin + XmupParamConstant.EQUAL).append(tokenPayInfo.getTokenBegin()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != tokenPayInfo.getTokenEnd() && !tokenPayInfo.getTokenEnd().isEmpty()) {
            tokenPayData.append(XmupTreeNodeConstant.tokenEnd + XmupParamConstant.EQUAL).append(tokenPayInfo.getTokenEnd()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != tokenPayInfo.getTokenType() && !tokenPayInfo.getTokenType().isEmpty()) {
            tokenPayData.append(XmupTreeNodeConstant.tokenType + XmupParamConstant.EQUAL).append(tokenPayInfo.getTokenType()).append(XmupParamConstant.AMPERSAND);
        }
        tokenPayData.setLength(tokenPayData.length() - 1);
        tokenPayData.append(XmupParamConstant.RIGHT_BRACE);
        xmlTreeUtil.setXmlTreeStringValue(XmupTreeNodeConstant.tokenPayData, tokenPayData.toString());
    }


    /**
     * 风控信息KV转换处理
     *
     * @param riskCtrlInfo 风控信息
     * @throws Exception 异常
     */
    protected void packageRiskCtrlInfo(RiskCtrlInfo riskCtrlInfo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        StringBuilder riskCtrlData = new StringBuilder(XmupParamConstant.LEFT_BRACE);
        if (null != riskCtrlInfo.getShippingFlag() && !riskCtrlInfo.getShippingFlag().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.shippingFlag + XmupParamConstant.EQUAL).append(riskCtrlInfo.getShippingFlag()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getShippingCountry() && !riskCtrlInfo.getShippingCountry().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.shippingCountryCode + XmupParamConstant.EQUAL).append(riskCtrlInfo.getShippingCountry()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getShippingProvince() && !riskCtrlInfo.getShippingProvince().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.shippingProvinceCode + XmupParamConstant.EQUAL).append(riskCtrlInfo.getShippingProvince()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getShippingCity() && !riskCtrlInfo.getShippingCity().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.shippingCityCode + XmupParamConstant.EQUAL).append(riskCtrlInfo.getShippingCity()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getShippingArea() && !riskCtrlInfo.getShippingArea().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.shippingDistrictCode + XmupParamConstant.EQUAL).append(riskCtrlInfo.getShippingArea()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getShippingStreet() && !riskCtrlInfo.getShippingStreet().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.shippingStreet + XmupParamConstant.EQUAL).append(riskCtrlInfo.getShippingStreet()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getGoodCategory() && !riskCtrlInfo.getGoodCategory().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.commodityCategory + XmupParamConstant.EQUAL).append(riskCtrlInfo.getGoodCategory()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getGoodName() && !riskCtrlInfo.getGoodName().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.commodityName + XmupParamConstant.EQUAL).append(riskCtrlInfo.getGoodName()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getGoodUrl() && !riskCtrlInfo.getGoodUrl().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.commodityUrl + XmupParamConstant.EQUAL).append(riskCtrlInfo.getGoodUrl()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getGoodPrice() && !riskCtrlInfo.getGoodPrice().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.commodityUnitPrice + XmupParamConstant.EQUAL).append(riskCtrlInfo.getGoodPrice()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getGoodNum() && !riskCtrlInfo.getGoodNum().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.commodityQty + XmupParamConstant.EQUAL).append(riskCtrlInfo.getGoodNum()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getShippingMobile() && !riskCtrlInfo.getShippingMobile().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.shippingMobile + XmupParamConstant.EQUAL).append(riskCtrlInfo.getShippingMobile()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getAddrModifyTime() && !riskCtrlInfo.getAddrModifyTime().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.addressModifyTime + XmupParamConstant.EQUAL).append(riskCtrlInfo.getAddrModifyTime()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getUserRegisterTime() && !riskCtrlInfo.getUserRegisterTime().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.userRegisterTime + XmupParamConstant.EQUAL).append(riskCtrlInfo.getUserRegisterTime()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getReceiptNameModifyTime() && !riskCtrlInfo.getReceiptNameModifyTime().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.orderNameModifyTime + XmupParamConstant.EQUAL).append(riskCtrlInfo.getReceiptNameModifyTime()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getUserId() && !riskCtrlInfo.getUserId().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.userId + XmupParamConstant.EQUAL).append(riskCtrlInfo.getUserId()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getReceiptName() && !riskCtrlInfo.getReceiptName().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.orderName + XmupParamConstant.EQUAL).append(riskCtrlInfo.getReceiptName()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getUserFlag() && !riskCtrlInfo.getUserFlag().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.userFlag + XmupParamConstant.EQUAL).append(riskCtrlInfo.getUserFlag()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getMobileModifyTime() && !riskCtrlInfo.getMobileModifyTime().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.mobileModifyTime + XmupParamConstant.EQUAL).append(riskCtrlInfo.getMobileModifyTime()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getRiskLevel() && !riskCtrlInfo.getRiskLevel().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.riskLevel + XmupParamConstant.EQUAL).append(riskCtrlInfo.getRiskLevel()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getMchntUserId() && !riskCtrlInfo.getMchntUserId().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.merUserId + XmupParamConstant.EQUAL).append(riskCtrlInfo.getMchntUserId()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getMchntUserRegTime() && !riskCtrlInfo.getMchntUserRegTime().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.merUserRegDt + XmupParamConstant.EQUAL).append(riskCtrlInfo.getMchntUserRegTime()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getMchntUserRegEmail() && !riskCtrlInfo.getMchntUserRegEmail().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.merUserEmail + XmupParamConstant.EQUAL).append(riskCtrlInfo.getMchntUserRegEmail()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getDiskSeqNo() && !riskCtrlInfo.getDiskSeqNo().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.diskSep + XmupParamConstant.EQUAL).append(riskCtrlInfo.getDiskSeqNo()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getImei() && !riskCtrlInfo.getImei().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.imei + XmupParamConstant.EQUAL).append(riskCtrlInfo.getImei()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getImei() && !riskCtrlInfo.getImei().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.imei + XmupParamConstant.EQUAL).append(riskCtrlInfo.getImei()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getMacAddr() && !riskCtrlInfo.getMacAddr().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.macAddr + XmupParamConstant.EQUAL).append(riskCtrlInfo.getMacAddr()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getLongitudeAndLatitude() && !riskCtrlInfo.getLongitudeAndLatitude().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.lbs + XmupParamConstant.EQUAL).append(riskCtrlInfo.getLongitudeAndLatitude()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getDeviceNo() && !riskCtrlInfo.getDeviceNo().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.deviceNumber + XmupParamConstant.EQUAL).append(riskCtrlInfo.getDeviceNo()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getDeviceType() && !riskCtrlInfo.getDeviceType().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.deviceType + XmupParamConstant.EQUAL).append(riskCtrlInfo.getDeviceType()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getCaptureMethod() && !riskCtrlInfo.getCaptureMethod().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.captureMethod + XmupParamConstant.EQUAL).append(riskCtrlInfo.getCaptureMethod()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getSimCardNum() && !riskCtrlInfo.getSimCardNum().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.simCardCount + XmupParamConstant.EQUAL).append(riskCtrlInfo.getSimCardNum()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != riskCtrlInfo.getDeviceName() && !riskCtrlInfo.getDeviceName().isEmpty()) {
            riskCtrlData.append(XmupTreeNodeConstant.deviceName + XmupParamConstant.EQUAL).append(riskCtrlInfo.getDeviceName()).append(XmupParamConstant.AMPERSAND);
        }
        riskCtrlData.setLength(riskCtrlData.length() - 1);
        riskCtrlData.append(XmupParamConstant.RIGHT_BRACE);
        xmlTreeUtil.setXmlTreeStringValue(XmupTreeNodeConstant.riskRateInfo, riskCtrlData.toString());
    }

    /**
     * 付款方信息域kv转换处理
     *
     * @param payerInfo 付款方信息
     * @throws Exception 异常
     */
    protected void packagePayerInfo(PayerInfo payerInfo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        StringBuilder payerVerifiInfo = new StringBuilder(XmupParamConstant.LEFT_BRACE);
        if (null != payerInfo.getPayerAccNo() && !payerInfo.getPayerAccNo().isEmpty()) {
            payerVerifiInfo.append(XmupTreeNodeConstant.payerAccNo + XmupParamConstant.EQUAL).append(payerInfo.getPayerAccNo()).append(XmupParamConstant.AMPERSAND);
        }
        if (null != payerInfo.getPayerName() && !payerInfo.getPayerName().isEmpty()) {
            payerVerifiInfo.append(XmupTreeNodeConstant.payerNm + XmupParamConstant.EQUAL).append(payerInfo.getPayerName()).append(XmupParamConstant.AMPERSAND);
        }
        payerVerifiInfo.setLength(payerVerifiInfo.length() - 1);
        payerVerifiInfo.append(XmupParamConstant.RIGHT_BRACE);
        xmlTreeUtil.setXmlTreeStringValue(XmupTreeNodeConstant.payerVerifiInfo, payerVerifiInfo.toString());
    }

    protected T convertKvStr2Bean(String kvStr, Class<T> beanClass) throws Exception {
        Map<String, Object> kvMap = XmupSecurityUtil.parseKvString(kvStr);
        JSONObject jsonObject = new JSONObject(kvMap);
        return JSON.parseObject(jsonObject.toJSONString(), beanClass);
    }

}
